-----------基础知识-------

java基本数据类型
byte  	1字节
short 	2字节
int 	4字节
Long 	8字节
float 	4字节
double  8字节
char 	2字节
boolean 1字节

--抽象类和接口的区别--



--线程池配置参数---
 核心线程数
 最大线程数
 淘汰策略(达到最大线程数时)
 线程空闲时间(非核心线程空闲时存活时间)
 时间单位
 线程工厂(可以定义名称和优先级)
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4,                             // corePoolSize
    8,                             // maximumPoolSize
    60,                            // keepAliveTime
    TimeUnit.SECONDS,              // unit
    new LinkedBlockingQueue<>(100),// workQueue
    new NamedThreadFactory("app-thread"), // threadFactory
    new ThreadPoolExecutor.CallerRunsPolicy() // rejectedExecutionHandler
);

--mybatis ${} 和 #{}的区别---
#{}防止sql注入，会使用预编译，对参数会默认加上''
${} 不会，适合动态字段或表，例如  order by ${cloumns}


--arrayList和linkedLis区别



阻塞队列(Blocking Queue)是Java并发包(java.util.concurrent)中提供的一种特殊队列，它在队列操作(入队/出队)时提供阻塞能力，是多线程编程中常用的线程同步工具。
		1. ArrayBlockingQueue
		基于数组的有界阻塞队列

		固定大小，构造时必须指定容量

		可选择公平性(公平模式下按FIFO顺序处理等待线程)

		典型应用：固定大小的线程池工作队列
		BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
		2. LinkedBlockingQueue
		基于链表的可选有界阻塞队列
		默认无界(Integer.MAX_VALUE)，也可指定容量
		吞吐量通常高于ArrayBlockingQueue
		典型应用：Executors.newFixedThreadPool()的工作队列
		BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);
		3. PriorityBlockingQueue
		带优先级的无界阻塞队列
		元素必须实现Comparable接口或提供Comparator
		不保证同等优先级元素的顺序
		典型应用：需要按优先级处理任务的场景
		BlockingQueue<Task> queue = new PriorityBlockingQueue<>();
		4. DelayQueue
		延迟元素的无界阻塞队列
		元素必须实现Delayed接口
		只有延迟期满的元素才能被取出
		典型应用：定时任务调度、缓存过期
		BlockingQueue<Delayed> queue = new DelayQueue<>();
		5. SynchronousQueue
		不存储元素的阻塞队列
		每个插入操作必须等待对应的移除操作
		吞吐量通常高于LinkedBlockingQueue和ArrayBlockingQueue
		典型应用：Executors.newCachedThreadPool()的工作队列
		BlockingQueue<Object> queue = new SynchronousQueue<>();
---------------Elasticsearch------------ 
match查询和term查询的区别
match 对


springcloud 
1、服务发现注册 eureka
(nacos)
2、rebbon 客户端负载均衡
3、熔断限流hystrix
	* 服务降级: 返回fallback
	* 服务熔断: 返回自定义的返回方法
	* 服务隔离：隔离服务之间相互影响
	* 服务监控：在服务发生调用，将一些操作数据记录下来
4、feign调用
5、spring config注册中心
6、网关 zuul（getway）

--------------jvm---------------
jvm类加载过程：
1、加载
	* 通过类的全限定名获取这个类的二进制字节流
	* 将这个字节流的静态存储结构转化为方法区的运行时数据结构，包括创建运行时常量池，将类常量池部分符号引用放入运行时常量池
	* 在内存中生成这个类的java.lang.Class对象，作为方法区这个类各种数据的访问入口
2、链接
	1、验证 
		验证文件是否符合jvm解析条件
	2、准备
		为类变量分配空间，并赋0值
	3、解析
		将方法区-运行时常量池中的符号引用转为直接引用
3、初始化
	为类变量显式赋值，执行静态代码块
jvm底层模型jvm调优参数：
Xmn 年轻代大小
Xmx	堆最大大小
Xms 堆初始大小
Xss 栈大小
newRatio 年轻代：老年代
survivorRatio(eden:survivor)
MaxTenuringThreshold=15 设置垃圾最大年龄

类加载子系统：
运行时数据区：
	虚拟机栈：
		局部变量表
		动态链接：方法外部引用
		操作数栈：操作
		方法返回地址
	本地方法栈：存放本地方法，用c语言实现
	方法区：存放类变量信息
	堆：存放对象
	程序计数器：存放下一个指令的地址
执行引擎：执行字节码

CMS的垃圾回收原理
标记清除算法：
		1、标记GC-ROOT直接引用，会stw，时间很短
		2、并发标记 以直接引用，并发标记所有关联对象
		3、重复标记，校正可达状态
		4、并发清楚不可达对象
	
-----------------------hashMap-------------------------

HashMap的put方法的总结
判断table是否为空，如果空的话，会先调用resize扩容；
根据当前key的 hash 值，通过 (n - 1) & hash计算应当存放在数组中的下标 index ；
查看 table[index] 是否存在数据，没有数据就构造一个 Node 节点存放在 table[index] 中；
存在数据，说明发生了 hash 冲突，继续判断 key 是否相等，如果相等，用新的 value 替换原数据(这里onlyIfAbsent 为 false)；
如果不相等，判断当前节点类型是不是树型节点，如果是树型节点，创建树型节点插入红黑树中；
如果不是树型节点，则采用尾插法，把新节点加入到链表尾部；判断链表长度是否大于 8， 大于的话，再判断数组长度是否小于64，小于则扩容，大于则链表转换为红黑树；
插入完成之后判断当前节点数是否大于阈值，如果大于开始扩容为原数组的二倍。

数组+链表
将key通过hash计算，得到hashCode，对数组长度取膜，得到数组的索引下表。
1.8对hash算法做了优化：
将hashCode（int值，32位）二进制右移16位和原code进行异或运算（相同为1，不同为0），
使hashCode低16位同时具有高16位和低16位的特征，尽量避免hash冲突---》后续寻址算法会计算位置


寻址算法优化：
与运算替代取模，提升性能。
hash对n取模效果 == hash & (n-1)  与运算（相同为0 不同为1） n为数组长度，为2的m次方

hashMap解决hash冲突：
当计算的hashCode相同时，将放置到同一数组下表内，get的时间复杂度为O(n)
当长度达到一定长度时，链表转化为红黑树O(lognN)

ConcurrentHashMap是Java中线程安全的哈希表实现，它在JDK 1.7和JDK 1.8中有不同的实现方式：
JDK 1.7及之前版本
分段锁(Segment)机制：将整个哈希表分成多个Segment(默认16个)，每个Segment相当于一个小的HashMap
每个Segment独立加锁(内部采用链表解决hash冲突)，不同Segment的操作可以并发进行
通过减小锁的粒度提高并发性能

JDK 1.8及之后版本
CAS + synchronized优化：取消了分段锁设计
使用Node数组+链表/红黑树的结构（类似HashMap）
对每个桶(bucket)的第一个节点加锁(synchronized)
大量使用CAS操作(如sizeCtl、扩容等)提高并发性能
当链表长度超过阈值(默认8)时转换为红黑树

--------------------------redis-----------------------------------
redis
1、缓存击穿、缓存穿透、缓存雪崩 解决方案

	* 缓存击穿（热点key失效，大量用户访问）
		① 同雪崩
	* 缓存穿透（大量请求访问不存在的key）
		① 对空值进行缓存（设置value为空）
		② 对redis进行实时监控，把问题ip或请求拦截
		③ 使用布隆过滤器，将目前所有的数据映射到布隆过滤器中，当有个请求过来的时候，先通过布隆过滤器判断，有则放行，否则拦截
		④ 接口拦截，对不符合业务数据规范的请求进行拦截
	* 缓存雪崩（大范围key过期）
		① 预先热门词汇的设置，进行key时长调整
		② 实施调整，监控哪些数据是热门数据，实施调整key的过期时长
		③ 使用锁机制（redis查不到数据时，使用排它锁，其他线程等待）

----redis 快速的原因
1、纯内存操作
2、高效的存储结构：
	String：简单动态字符串(SDS)
	Hash：ziplist（元素少时）/hashtable
	List：quicklist（ziplist+linkedlist组合）
	Set：intset（纯整数时）/hashtable
	ZSet：ziplist（元素少时）/skiplist
3、单线程，避免了现成切换的开销（6.0后引入多线程-处理网络请求;但核心还是单线程）
---击穿解决方案
方案		优点					缺点								适用场景
互斥锁	保证数据一致性		存在短暂等待					数据强一致要求高
逻辑过期	无阻塞，用户体验好	短暂脏读						可容忍短暂不一致的热点数据
永不过期	完全避免击穿			数据更新不及时				极少变更的热点数据
多级缓存	减少Redis压力		增加复杂度，可能本地不一致		超高并发的热点数据

---redis过期策略
* 定期删除 默认100毫秒一次检查小范围过期的key进行删除【每次随机遍历设置了过期时间的key，如果已经过期，就直接删除】 (通过限制执行时长和频率，减少对cpu的影响)
		权衡策略，如果删除过于频繁，会影响redis的性能，如果删除不频繁，那么又会堆积大量过期的key。
* 惰性删除 当尝试访问一个key时，如果改key过期，则删除。（对cpu友好，可能堆积大量key会占用更多的内存）
将两者结合起来，就形成了Redis高效且实用的过期key删除机制


---内存淘汰策略
* redis 3.0默认不移除，当空间不足时插入，报错
* 移除最少使用的key
* 随机移除某个key
* 移除设置了过期时间中，最少使用的key
* 移除设置了过期时间中，随机某个key
* 移除设置了过期时间中

布隆过滤器：
**作用：
	检查一个元素是否在集合内
**优点：
*	增加和查询速度快，
*	保密性强，不存储元素本身；
*	存储空间小，节省空间
布隆过滤器由一个二进制数组和一系列hash函数组成。

***
---redis io模型 
*** io多路复用：
一个线程监控多个文件句柄，当有文件句柄就绪时，通知线程进行读写操作。
三种方式实现：
select()
采用轮询遍历，每次调用需要将文件标识符（fd）集合从用户态拷贝到内核态，而且单个线程打开的fd是有限制的，默认1024个
poll()
跟select大致一样，主要区别就是fd数量无限制
epoll()
只能在linux系统下工作，用户态拷贝到内核态只需要一次，通过epoll_tcl函数注册fd，
一旦有fd就绪后，就会通过callback回调机制来激活对应fd，进行相关的io操作。
高性能得益于以下函数：
epoll_create()系统启动时，在linux内核中申请一个b+树结构文件系统，返回epoll对象，也就是一个fd
epoll_ctl()每新建一个连接，都通过该函数进行操作epoll对象，在这个对象里修改添加删除对应的连接fd，并绑定一个callback函数。
epoll_wait()轮询所有的call_back集合，完成对应的IO操作


// 设置值并设置过期时间
redisTemplate.opsForValue().set("key", "value", 60, TimeUnit.SECONDS);
// 只有key不存在时设置
Boolean setIfAbsent = redisTemplate.opsForValue().setIfAbsent("key", "value");
// 获取值
Object value = redisTemplate.opsForValue().get("key");
// 设置hash值
redisTemplate.opsForHash().put("hashKey", "field", "value");
// 获取hash值
Object hashValue = redisTemplate.opsForHash().get("hashKey", "field");
// list左插入
redisTemplate.opsForList().leftPush("listKey", "value");


压缩列表（ziplist） 是 Redis 为了节省内存而开发的，是由一系列特殊编码的连续内存块组成的顺序型数据结构，
一个压缩列表可以包含任意多个节点（entry），每个节点可以保存一个字节数组或者一个整数值。
**hash ziplist 和 hashtable 两种。当哈希对象保存的键值对数量小于 512 并且所有键值对的长度都小于 64 字节时，使用压缩列表存储；否则使用 hashtable 存储。
**list 列表对象的编码有 ziplist 和 linkedlist 两种。当列表的长度小于 512，并且所有元素的长度都小于 64 字节时，使用压缩列表存储，否则使用 linkedlist 存储。
**set 列表对象的编码有 intset 和 hashtable 两种。当集合的长度小于 512，并且所有元素都是整数时，使用整数集合存储；否则使用 hashtable 存储。
**sort set 有序集合对象的编码有 ziplist 和 skiplist 两种。当有序集合的长度小于 128，并且所有元素的长度都小于 64 字节时，
	使用压缩列表存储；否则使用 skiplist 存储。
为什么要用redis
	* redis是基于内存，没有磁盘IO的开销
	* 高效的存储结构{sds,hash,跳表,压缩链表}
	* 合理的线程模型{单线程模式，避免上下文切换 io多路复用（一个线程操作多个文件）}
	
			命令	RDB		AOF
启动优先级	低		高
体积			小		大
恢复速度		快		慢
数据安全性	丢数据	取决于刷盘策略
轻重			重		轻
	
布隆过滤器可以应对缓存穿透问题
数据结构：一个很长的二进制向量和一组Hash映射函数组成。
作用：检索一个元素是否在一个集合中，空间查询效率比一般的算法要好的多
缺点：有一定误识别率和删除困难。
原理：集合A中有n个元素，利用K个哈希散列函数，将A中每个元素映射到一个长度为a位的数组B中不同位置上。
这些位置上的二进制数均设置为1。经过这个K个哈希散列函数映射后，发现其k个位置上的二进制数全部为1，这个元素很可能属于集合A。

redis集群原理
对数据进行分片


-------------------数据库------------------
联合索引
数据库传播级别：
	* 读未提交 一个事务可以读取另外一个事务未提交的数据  ---导致脏读、幻读、不可重复读问题
	* 读已提交（oracle默认隔离级别） 一个事务读取过程中，读取了别人已提交的数据，形成前后数据不一致 ---不可重复读问题 
	* 可重复读（mysql默认隔离级别） 解决不可重复读问题
	* 序列化 事务串行进行，安全性最高，但效率低下
	
mysql与oracle语法区别

				mysql															oracle
时间转字符串  	date_format(now(),'%Y-%m-%d') 									to_char(sysdate, 'YYYY-MM-DD')
字符串转时间		str_to_date('2020-02-01','%Y-%m-%d')							to_date('2020-02-01','YYYY-MM-DD')
条件函数			if(value=a,b,c)													decode(value,a,b,c)
trunc函数		truncate(12.21)=12	trunc(12.21)=12; 							trunc(12.332,3)=12.33	
格式转换			转化数字 cast('123' as signed);字符串 cast(123 as char(3))   		to_char(123) to_number('123')

EXPLAIN PLAN FOR
SELECT * FROM your_table WHERE your_column = 'some_value';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

锁：
互斥锁:线程加锁失败后，会把该线程设置sleep，线程释放cpu给其他线程，等线程释放锁后，再恢复操作
自旋锁（CAS）:加锁失败会一直等待，直到获取锁
读写锁:写独占，读共享。适合写操作少的时候
悲观锁:
乐观锁:默认没有发生冲突，等修改完成，如果期间数据已经被修改过，就放弃本次操作

mysql窗口函数之排序
1、row_number() 	去重排序 		1234567
2、rank() 			跳跃排序   		1133567
3、dense_rank() 	连续排序		1122345
-----start-----
 dense_rank() over(partition by 分组字段 order by 排序字段 desc) as '序号命名'
------end------

单例、多例、双重检查锁(单例懒加载)
单例使用场景：
1、读取配置文件，不可能每次new 对象，每次去读取文件，很影响性能
2、比如在不考虑分布式场景，使每个用户在相同时刻获取人数数量都是一致的
3、数据库连接池，包括线程池，减少新建连接，初始化的开销
实现方法：静态内部类（懒汉式），枚举方式

binlog row 记录每一行的数据 
statement 记录每一条修改语句 
mixed对于statement记录不了的采用row来记录

优化
1、写法上避免隐式转换
2、劲量默认设置初始值，避免is null和 is not null or <>使索引失效
3、适当创建联合索引，减少后期回表，，最左前缀原则，和b+树结构有关，索引排序方式:先按第一个进行排序，如果相等再第二个
4、避免在索引列做任何计算
5、范围查询后面的条件都会失效

mysql锁
操作粒度：行锁、表锁、页锁
操作类型：读锁、写锁
操作性能：乐观锁、悲观锁

加锁范围：表级锁、行级锁、全局锁

全局锁：
	以整个数据库为对象进行加锁
		方式1：flush tables with read lock（数据库异常时会释放锁，unlock tables）
		方式2：set golbal readonly = true 
表级锁（偏读）:
	共享锁(读锁)：
	排它锁(写锁)：
行锁升级为表锁：
	当对索引字段加锁，，在不通过索引查询时，innodb就会使用表锁


----一颗B+Tree可以存放多少数据
MySQL设计者将一个B+Tree的节点的大小设置为等于一个页. (这样做的目的是每个节点只需要一次I/O
就可以完全载入), InnoDB的一个页的大小是16KB,所以每个节点的大小也是16KB, 并且B+Tree的根节点
是保存在内存中的,子节点才是存储在磁盘上
假设一个B+树高为2，即存在一个根节点和若干个叶子节点，那么这棵B+树的存放总记录数为：根节点
指针数*单个叶子节点记录行数.
计算根节点指针数: 假设表的主键为INT类型,占用的就是4个字节,或者是BIGINT占用8个字节, 指针
大小为6个字节,那么一个页(就是B+Tree中的一个节点) ,大概可以存储: 16384B / (4B+6B) = 1638 ,
一个节点最多可以存储1638个索引指针.
计算每个叶子节点的记录数:我们假设一行记录的数据大小为1k,那么一页就可以存储16行数
据,16KB / 1KB = 16.
一颗高度为2的B+Tree可以存放的记录数为: 1638 * 16=26208 条数据记录, 同样的原理可以推算
出一个高度3的B+Tree可以存放: 1638 * 1638 * 16 = 42928704条这样的记录.
所以InnoDB中的B+Tree高度一般为1-3层,就可以满足千万级别的数据存储,在查找数据时一次页的查找
代表一次 IO，所以通过主键索引查询通常只需要 1-3 次 IO 操作即可查找到数据。



--------------------spring---------------
spring bean生命周期
实例化
属性赋值
初始化
销毁 destory方法--实现BisposableBean接口

5种IO模型：
1、堵塞IO模型
2、非堵塞IO模型
3、复用IO模型（select,poll,epoll)
4、信号驱动IO模型（异步非阻塞IO）
5、异步IO模型

** BIO（同步堵塞）
服务器采用单线程，只能处理一个操作，无法并发
服务器采用多线程，会增大线程开销，造成资源浪费

** NIO（同步非堵塞）
当服务端接受一个请求，加入fd集合，每次轮询一遍fd集合数据，没有则立即返回错误

spring容器初始化：
1、启动阶段
通过springDefinationReader读取配置信息，生成元信息类BeanDefination对象，并将其注册到BeanDefinationRegister对象中
BeanFactoryPostProcess将会对注册的BeanDefination对象进行最后的修改，替换占位符，完成真实数据的注入
2、获取bean阶段
如果配置了懒加载，则在获取该对象实例前，bean对象以beanDefination形式存储在BeanDefinationRegister内
先判断缓存或BeanFactory中是否存在bean对象，不存在则调用getBean获取

//https://blog.csdn.net/a745233700/article/details/113840727?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171919383816800182136399%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171919383816800182136399&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~hot_rank-5-113840727-null-null.nonecase&utm_term=springbean%E7%9A%84%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B&spm=1018.2226.3001.4450

线程池：拒绝策略：
任务丢失，抛出运行时异常
什么都不做
执行
提出最先进入队列的任务
实现rejectedExecutionHandler接口，可自定义处理器



敏感词 

root->赌->博
root->赌->场

构建前缀树TempNode 内部两个属性 敏感词结束标、Map<Character,TempNode>
遍历文本内容
判断是否为符号{
如果不是敏感词中间的符号，就追加到结果文本中
}
双指针检测 双指针刚开始在链表头位置，找到敏感词前缀，二指针移动，如果找到敏感词结束标志，一指针移动到二指针位置。
如果未找到敏感词位置，一指针向前移动一个位置，二指针回到一指针位置。然后再判断一指针当前是不是敏感词前缀。。。


#除了从sql层面，怎么优化查询
系统层面上优化：
1. 数据库设计优化
	合理设计表结构：遵循规范化原则但避免过度规范化
	适当使用反范式化：在关键查询路径上增加冗余字段减少JOIN操作
	选择合适的数据类型：使用最小够用的数据类型减少存储和I/O
	分区表设计：对大表按时间、范围等维度分区
2. 索引策略优化
	覆盖索引：确保索引包含查询所需的所有字段
	复合索引顺序：将高选择性字段放在前面
	函数索引：为常用函数查询创建特殊索引
	定期重建索引：解决索引碎片问题
3. 缓存策略
	应用层缓存：使用Redis/Memcached缓存热点数据
	查询结果缓存：对频繁执行的相同查询缓存结果
	数据库缓存：合理配置数据库缓冲池大小
4. 硬件和配置优化
	增加内存：扩大数据库缓冲池
	使用SSD：提升I/O性能
	优化数据库参数：调整连接数、排序缓冲区等参数
	读写分离：将读操作分流到从库
5. 架构层面优化
	分库分表：水平/垂直拆分大表
	使用CDN：对静态内容加速
	异步处理：将非实时需求改为异步处理
	微服务化：将大应用拆分为专注的小服务
6. 应用层优化
	批量操作：减少频繁的单条操作
	延迟加载：按需获取数据
	预计算：提前计算复杂聚合结果
	连接池管理：合理使用和管理数据库连接

软件层面上：
	【1】调整innodb内存池大小 innodb_buffer_pool_size，正常设置大小在系统内存的50-70%
	【2】清理日志文件：mysql的错误日志，二进制日志，慢查询日志等日志文件肯可能会占用大量存储空间
	【3】清理未使用的表和索引，占用存储空间
	【4】清理无用的备份文件，保留最新的有效文件
	【5】优化存储方式，可以适当更改存储引擎
	【6】创建适量索引	
	【7】配置最大连接数max_connections，正常来说最大连接数应该要大于服务器并发连接数
	【8】分库分表：
			垂直分库：将大型的数据库拆分为多个小数据库，每个库中包含一部分表，缺点：数据一致性
			水平分库：将大型数据库的表按某种规则分散到多个小数据库中，一个小数据库包含一部分表，缺点：数据一致性
			水平分表：将大数据表，比如按id范围分到不同的表中。缺点是可能导致查询水平下降


可达性分析算法：
以GC-ROOT为根节点，向下查找，对直接或间接引用的对象头上标记可达
标记完，对不可达对象判断是否有必要执行finalize方法，并放入F-Queue队列中，过段时间会执行finalize方法。如果执行完未有引用关系，则会被垃圾回收


spring bean的创建流程：
加载bean信息
1、实例化bean
	createBeanInstance
2、设置属性值
3、调用对应的aware方法
4、BeanPostProcess前置处理
5、initialingBean处理
6、init-method处理
7、BeanPostProcess后置处理



三级缓存
一级缓存singletonObjects，存放完全初始化好的bean
二级缓存earlySingletonObjects已经创建但是尚未完全初始化（如属性填充和初始化方法的调用）
三级缓存singletonFactorys 存放bean的工厂对象
为什么不能用二级缓存
此时B相当于从三级缓存中拿到了A的代理对象，B为了后面的C和自己拿到的是同一个A的代理对象，
他就需要把这个A代理对象放入第二级缓存。同时移除第三级缓存的A，表示A已经提前创建好了代理对象，不需要再从三级缓存里面获取新代理对象了。
接下来，B的创建好后，A继续注入C，C直接从第二级拿到已经创建好了的A的代理对象。A在后面的初始化阶段执行
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
		// Consistent creation of early reference within full singleton lock
		singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null) {
		ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
		if (singletonFactory != null) {
		singletonObject = singletonFactory.getObject();
		this.earlySingletonObjects.put(beanName, singletonObject);
		this.singletonFactories.remove(beanName);
		}
		}
		}
		}
		}
		}
		return singletonObject;
		}



		bean生命周期
1、创建（实例化、属性填充）
2、初始化
3、使用
4、销毁

spring bean创建过程
1、加载bean信息
	将扫描到的类形成beanDefinition对象，存放bean的一些属性特征，如bean名称、路径、是否单例等信息
	通过beanDefinitonRegister加载beanDefinition信息
2、实例化bean 
	通过尝试 getBean=》doGetBean=》getSingleton 去获取bean，
	如果获取不到再启动创建过程(扫描autoware注解：ConstructorResolver.autowireConstructor())
3、填充属性
	popuateBean(beanName,beanDefination)，根据beanDefination判断是按名称注入还是按类型，并调用getSingleton获取所需对象去获取对应单例。
	通过autoware内置处理器调用postProcessProperties注入属性
4、初始化对象
	判断有无实现aware接口，获取容器所有的postProcess接口，执行前置方法
4、后置操作
	清理三级缓存，二级缓存中无用的bean引用。将bean添加到单例池


mysql存储过程 innodb\mysam
区别：innodb支持事务,mysam不支持


bean销毁是实现disposeBean接口，重写destory方法

threadlocal使用场景及原理
线程内部维护了一个threadlocalMap变量
而threadLocalMap 由entry数组组成，entry对象内部包含了threadlocal对象和其泛型值。 entry类实现了弱引用
get的时候通过hash寻址计算key位置，获取对应的entry对象，返回其value

为什么要用弱引用：
如果ThreadLocal变量被手动设置为null时，此时只有Entry有对ThreadLocal的弱引用，
那么当系统GC时就会回收ThreadLocal弱引用，value在下次调用ThreadLocal的set,get，remove方法的时，
因为key为null，所以会被清除。如果是强引用，那么Entry对ThreadLocal不会回收，那么obiect不会被清除。

**mysql读已提交和可重复度 mvcc的实现区别
MySQL实现MVCC机制的方式: undo log多版本链+ReadView机制
读已提交在一次事务中，每次查询，会生成一个readView
而可重复读，只会在第一个select时生成一个readView

spring事务
	--mysql:
		-- 开启事务
		start transaction;

		-- 业务执⾏
		-- 提交事务
		commit;
		-- 回滚事务
		rollback;
1、编程式事务（手写代码操作事务）



2、声明式事务（利用注解自动开启和提交事务）
@Transactional
只能应用在public方法上

实现原理：APO==>动态代理（jdk/cdlib 实现了接口用jdk，否则用cglib）
通过transactionInsterceptor拦截器
Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置
7种传播级别：
	1、默认REQUIRED(需要):如果当前存在事务，则加入事务，如果不存在则创建新事务。A方法调用B方法
	2、SUPPORTS(支持):如果当前存在事务，则加入事务，不存在则不创建事务
	3、MANDOTRY(强制性的)：如果当前存在事务，则加入事务，不存在则抛出异常
	4、REQUIRES_ENW(需要新的)：会创建一个新的事务，与外界事务相互独立，互不干扰
	5、NOT_SUPPORTED(不支持的)：以非事务方式执行操作，如果当前存在事务，则把当前事务挂起。
	6、NEVER：不能在事务中执行，以非事务方式执行操作。如果当前存在事务，则抛出异常。
	7、NESTED(嵌套)：如果当前存在事务，则创建一个事务作为当前事务的嵌套事务来运行；如果当前没有事务，则与REQUIRED类似。

spring会为目标bean创建一个代理对象，通过@Transactional注解的行为织入到这个代理中。
如果A方法和B方法都在同一个类的实例内部相互调用，那么调用不会通过代理对象进行，因此@Transactional注解的行为（如事务管理）不会被触发。
		linux常用命令：
		ls  展示文件列表
		pwd 展示当前目录
		cd  切换文件目录
		mv  移动文件
		cp  拷贝文件
		rmdir 删除目录
		rm  删除文件
		cat 查看文件
		chmod(change mode) 改变文件或目录权限
		chown 改变文件所有权
		top 查看系统资源实时使用情况
		ps  查看当前系统所有线程使用情况
		grep 在文件中搜索文本 (grep 搜索词 文件名) 返回行数
		kill 终止进程
		df、du  显示磁盘使用情况 (du -h 指定目录、df -h）
		ping 测试主机连通性
		ifconfig 查看配置网口信息
		netstat 显示网络活动
		ssh 远程链接到其他主机


		常用设计模式
		单例模式
		观察者模式：在我改变一个类的时候，所有依赖于这个类的对象都会得到通知并自动更新
		策略模式：定义一些列算法，把他们一个个封装起来

-------------------linux常用命令----------------------
ls  展示文件列表
pwd 展示当前目录
cd  切换文件目录
mv  移动文件
cp  拷贝文件
rmdir 删除目录
rm  删除文件
cat 查看文件
	grep 搜索文件(包含高亮等)
less 分页查看文件，适合看大文件
chmod(change mode) 改变文件或目录权限
chown 改变文件所有权
top 查看系统资源实时使用情况
ps  查看当前系统所有线程使用情况
grep 在文件中搜索文本 (grep 搜索词 文件名) 返回行数
kill 终止进程
df、du  显示磁盘使用情况 (du -h 指定目录、df -h）
ping 测试主机连通性
ifconfig 查看配置网口信息
netstat 显示网络活动
ssh 远程链接到其他主机


常用设计模式
单例模式
观察者模式：在我改变一个类的时候，所有依赖于这个类的对象都会得到通知并自动更新
策略模式：定义一些列算法，把他们一个个封装起来


对于指定查询某一条记录的加锁语句, 如果该记录不存在, 会产生记录锁和间隙锁,如果记录存在,则
只会产生记录锁

接口和抽象类的区别

抽象类可以方法声明、实现
接口只能声明，不能实现
抽象类变量是普通变量，接口是公共静态变量
接口的抽象级别更高，通过其他类实现。单继承多实现
抽象类可以有具体方法和属性，接口只有抽象方法和不可变常量

线程用的包
java.util.concurrent
实现线程的几种方式
1、继承Thread类，重写run方法
2、实现Runnable接口，重写run方法
3、实现callable接口，重写run方法
4、使用线程池创建线程

常用一致性哈希分片 hash环（0-2^32）,当新增节点，如果顺时针有A、B、D三个节点，在BD中间插入C，那么原本在D的数据将会迁移部分数据到C中
cluster集群使用hash槽。通过crc算法得出的结果，把结果对16384(2^14)取模，得到一个0~16384，通过这个值找到对应槽

数据倾斜和访问倾斜时，前提可以业务层面提前预测，哪些是key热点，在设计中规避
后期是slot迁移，尽量将压力分担（调整方式有balance、reshard、手动）

Object包常用方法
isNull() toString() 
hasCode() 返回对象的哈希值（整数）

mysql 行锁条件

1、开启事务
2、根据索引加锁，当索引失效或者不存在会转化为表锁
3、innodb


nginx权重配置
upstream [域名] {
	server [ip] weight=1
}

开启锁条件
1、innodb引擎
2、开启事务(隔离界别为可重复读）



------------mq------------
MQ
Apache Kafka是由Apache开发的一种发布订阅消息系统，它是一个分布式的、分区的和重复的日志服务。
高吞吐量、低延迟：kafka每秒可以处理几十万条消息，它的延迟最低只有几毫秒，每个topic可以分多个partition, consumer group 对partition进行consume操作。
•可扩展性：kafka集群支持热扩展
•持久性、可靠性：消息被持久化到本地磁盘，并且支持数据备份防止数据丢失
•容错性：允许集群中节点失败（若副本数量为n,则允许n-1个节点失败）
•高并发：支持数千个客户端同时读写

分区对于 Kafka 集群的好处是：实现负载均衡。分区对于消费者来说，可以提高并发度，提高效率。


防止重复消费
业务上解决：
	* 消息幂等（调用多次和调用一次是一样的）可以requet头中放置唯一请求订单token，给对应token设置过期时间，相同token值不再处理
	* 消费者端消息去重（如利用主键冲突，再次插入会冲突，那样就不再处理这条消息）

延时消息了解吗？	
Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
    // 设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel)
message.setDelayTimeLevel(3);
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
延迟消息实现：临时存储+定时任务

死信队列：无法正常消费的消息会被推送到特殊队列（3天后会自动删除）
rocketmq提供了控制台查询、重发

与kafka对比
rocket支持延迟消息
存储结构不同，kafka存在partition，支持多副本。数据模型基于分区日志
rocketMq采用commit log统一存储

rocket顺序发送 ---同一业务id
// 同步顺序发送
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        // 根据业务参数选择队列，确保相同业务ID的消息进入同一队列
        Integer id = (Integer) arg;
        int index = id % mqs.size();
        return mqs.get(index);
    }
}, orderId); // orderId是业务ID